#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <wiringPi.h>
#include "types.h"

#include "i2c_protocol.h"

//保证每个函数结束的时候scl都是高电平

typedef struct{
	Pi2c_gpio gpio_handle;
	Pi2c_callback cb;
	i2c_print_level log_level;
}i2c_struct, *Pi2c_struct;

Pi2c_struct i2c_handle = NULL;

static void *i2c_malloc_fun(uint32 size)
{
	if(i2c_handle && i2c_handle->cb->malloc && size > 0)
		return i2c_handle->cb->malloc(size);
	return NULL;
}

static int i2c_free_fun(void *ptr)
{
	if(i2c_handle && i2c_handle->cb->free && ptr != NULL)
	{
		return i2c_handle->cb->free(ptr);
	}
	return -1;
}

static int i2c_delay_us_fun(uint32 time_us)
{
	if(i2c_handle && i2c_handle->cb->delay)
	{
		return i2c_handle->cb->delay(time_us);
	}
	return -1;
}

static int i2c_set_gpio_direction_fun(int gpio, uint8 direction)
{
	if(i2c_handle && i2c_handle->cb->set_gpio_direction)
	{
		return i2c_handle->cb->set_gpio_direction(gpio, direction);
	}
	return -1;
}

static int i2c_set_gpio_level_fun(int gpio, uint8 value)
{
	if(i2c_handle && i2c_handle->cb->set_gpio_level)
	{
		return i2c_handle->cb->set_gpio_level(gpio, (value>0)?1:0);
	}
	return -1;
}

static int i2c_get_gpio_level_fun(int gpio)
{
	if(i2c_handle && i2c_handle->cb->get_gpio_level)
	{
		return i2c_handle->cb->get_gpio_level(gpio);
	}
	return -1;
}

static int i2c_set_gpio_pullupdn(int gpio, gpio_pullupdn value)
{
	if(i2c_handle && i2c_handle->cb->set_gpio_pullupdn)
	{
		i2c_handle->cb->set_gpio_pullupdn(gpio, value);
		return 1;
	}
	return -1;
}

int i2c_log_write(i2c_print_level level, char *format, ...)
{
	if(i2c_handle)
	{
		if(i2c_handle->log_level >= level)
		{
			va_list arg;
			va_start(arg, format);
			vprintf(format, arg);
			va_end(arg);
		}
	}

	return 1;
}

int i2c_init(Pi2c_gpio gpio, Pi2c_callback cb, i2c_print_level log_level)
{
	if(i2c_handle || gpio == NULL || cb == NULL)
	{
		printf("ERROR IN %s:%d\n", __func__, __LINE__);
		return -1;
	}

	if(cb->malloc)
		i2c_handle = (Pi2c_struct)cb->malloc(sizeof(i2c_struct));
	if(i2c_handle == NULL)
	{
		printf("ERROR IN %s:%d\n", __func__, __LINE__);
		return -1;
	}
	if(cb->malloc)
		i2c_handle->cb = (Pi2c_callback)cb->malloc(sizeof(i2c_callback));
	if(i2c_handle->cb == NULL)
	{
		printf("ERROR IN %s:%d\n", __func__, __LINE__);
		return -1;
	}

	i2c_handle->log_level = log_level;

	memcpy(i2c_handle->cb, cb, sizeof(i2c_callback));

	if(i2c_handle->cb->malloc)
		i2c_handle->gpio_handle = (Pi2c_gpio)i2c_handle->cb->malloc(sizeof(i2c_gpio));
	if(i2c_handle->gpio_handle == NULL)
	{
		printf("ERROR IN %s:%d\n", __func__, __LINE__);
		return -1;
	}
	memcpy(i2c_handle->gpio_handle, gpio, sizeof(i2c_gpio));

	i2c_handle->cb->set_gpio_direction(i2c_handle->gpio_handle->gpio_scl, OUT_MODE); 
	i2c_set_gpio_direction_fun(i2c_handle->gpio_handle->gpio_scl, HIGH_LEVEL);
	i2c_set_gpio_direction_fun(i2c_handle->gpio_handle->gpio_sda, HIGH_LEVEL);

	return 0;
}

void i2c_deinit(void)
{
	I2C_FREE temp_free = NULL;
	if(i2c_handle == NULL)
		return;
	if(i2c_handle->gpio_handle)
		i2c_handle->cb->free(i2c_handle->gpio_handle);
	if(i2c_handle->cb)
	{
		temp_free = i2c_handle->cb->free;
		temp_free(i2c_handle->cb);
	}
	temp_free(i2c_handle);
	i2c_handle = NULL;
}

//success ---> >0, fail <= 0
//scl-->high
//sda-->high-->low
int8 i2c_start(void)
{
	if(i2c_handle == NULL)
		return 0;
	if(i2c_set_gpio_direction_fun(i2c_handle->gpio_handle->gpio_sda, OUT_MODE))
	{
		CHECK_ERROR(i2c_set_gpio_level_fun(i2c_handle->gpio_handle->gpio_scl, HIGH_LEVEL));
		CHECK_ERROR(i2c_set_gpio_level_fun(i2c_handle->gpio_handle->gpio_sda, HIGH_LEVEL));
		CHECK_ERROR(i2c_delay_us_fun(5));
		CHECK_ERROR(i2c_set_gpio_level_fun(i2c_handle->gpio_handle->gpio_sda, LOW_LEVEL));
		CHECK_ERROR(i2c_delay_us_fun(5));
		CHECK_ERROR(i2c_set_gpio_level_fun(i2c_handle->gpio_handle->gpio_scl, LOW_LEVEL));
		CHECK_ERROR(i2c_delay_us_fun(5));

		return 1;
	}
	return -1;
}

//success ---> >0, fail <= 0
//scl-->high
//sda-->low-->high
int8 i2c_stop(void)
{
	if(i2c_handle == NULL)
		return 0;
	if(i2c_set_gpio_direction_fun(i2c_handle->gpio_handle->gpio_sda, OUT_MODE))
	{
		CHECK_ERROR(i2c_set_gpio_level_fun(i2c_handle->gpio_handle->gpio_scl, LOW_LEVEL));
		CHECK_ERROR(i2c_delay_us_fun(5));
		CHECK_ERROR(i2c_set_gpio_level_fun(i2c_handle->gpio_handle->gpio_sda, LOW_LEVEL));
		CHECK_ERROR(i2c_delay_us_fun(5));
		CHECK_ERROR(i2c_set_gpio_level_fun(i2c_handle->gpio_handle->gpio_scl, HIGH_LEVEL));
		CHECK_ERROR(i2c_delay_us_fun(5));
		CHECK_ERROR(i2c_set_gpio_level_fun(i2c_handle->gpio_handle->gpio_sda, HIGH_LEVEL));
		CHECK_ERROR(i2c_delay_us_fun(5));

		return 1;
	}
	return -1;
}

//success ---> >0, fail <= 0
//sda-->0
//scl-->1
int8 i2c_ack_send(uint8 value)
{
	if(i2c_set_gpio_direction_fun(i2c_handle->gpio_handle->gpio_sda, OUT_MODE))
	{
		CHECK_ERROR(i2c_set_gpio_level_fun(i2c_handle->gpio_handle->gpio_scl, LOW_LEVEL));
		CHECK_ERROR(i2c_delay_us_fun(5));
		CHECK_ERROR(i2c_set_gpio_level_fun(i2c_handle->gpio_handle->gpio_scl, HIGH_LEVEL));
		CHECK_ERROR(i2c_delay_us_fun(5));
		CHECK_ERROR(i2c_set_gpio_level_fun(i2c_handle->gpio_handle->gpio_sda, value?0:1));
		CHECK_ERROR(i2c_delay_us_fun(5));

		return 1;
	}
	return -1;
}

//success ---> >0 , fail < 0
//sda-->0
//scl-->0-->1
int8 i2c_ack_read(void)
{
	int i = 300;
	uint8 ret = 1;
	if(i2c_handle->cb->set_gpio_direction(i2c_handle->gpio_handle->gpio_sda, IN_MODE))
	{
		CHECK_ERROR(i2c_set_gpio_level_fun(i2c_handle->gpio_handle->gpio_scl, LOW_LEVEL));
		CHECK_ERROR(i2c_delay_us_fun(5));
		i2c_set_gpio_pullupdn(i2c_handle->gpio_handle->gpio_sda, PULL_UP);
		CHECK_ERROR(i2c_delay_us_fun(5));
		CHECK_ERROR(i2c_set_gpio_level_fun(i2c_handle->gpio_handle->gpio_scl, HIGH_LEVEL));
		while(i--)
		{
			CHECK_ERROR(i2c_delay_us_fun(1));
			ret = i2c_get_gpio_level_fun(i2c_handle->gpio_handle->gpio_sda);
			if(ret == 0)
				break;
		}
		I2C_LOGI("%s:%d-->ret = %d\n", __func__, __LINE__, ret);
		CHECK_ERROR(i2c_delay_us_fun(10));

		i2c_set_gpio_pullupdn(i2c_handle->gpio_handle->gpio_sda, PULL_NO);
		CHECK_ERROR(i2c_set_gpio_level_fun(i2c_handle->gpio_handle->gpio_scl, LOW_LEVEL));

		if(ret >= 1)
			return -1;
		return ret;
	}
	return -1;
}

//success --->0, fail <= 1
//sda-->send value
//scl-->1
int8 i2c_byte_send(uint8 value)
{
	int i = 0;
	uint8 check_mask = 0x80;
	if(i2c_handle->cb->set_gpio_direction(i2c_handle->gpio_handle->gpio_sda, OUT_MODE))
	{
		i2c_set_gpio_pullupdn(i2c_handle->gpio_handle->gpio_sda, PUD_DOWN);
		I2C_LOGI("%s:%d---value = 0x%02x\n", __func__, __LINE__, value);
		for(i=7;i>=0;i--)
		{
			//value = (check_mask & value)?1:0;
			CHECK_ERROR(i2c_set_gpio_level_fun(i2c_handle->gpio_handle->gpio_scl, LOW_LEVEL));
			CHECK_ERROR(i2c_delay_us_fun(5));
			CHECK_ERROR(i2c_set_gpio_level_fun(i2c_handle->gpio_handle->gpio_sda, (value & check_mask)?1:0));
			CHECK_ERROR(i2c_delay_us_fun(5));
			CHECK_ERROR(i2c_set_gpio_level_fun(i2c_handle->gpio_handle->gpio_scl, HIGH_LEVEL));
			CHECK_ERROR(i2c_delay_us_fun(5));
			value = value << 1;
		}
		CHECK_ERROR(i2c_set_gpio_level_fun(i2c_handle->gpio_handle->gpio_scl, LOW_LEVEL));

		return i2c_ack_read();
		//return 1;
	}
	return -1;
}

//success --->0, fail <= 1
//sda-->read
//scl-->1
int8 i2c_byte_read(void)
{
	uint8 byte = 0, temp = 0;
	int i = 0;
	if(i2c_handle->cb->set_gpio_direction(i2c_handle->gpio_handle->gpio_sda, IN_MODE))
	{
		for(i=7;i>=0;i--)
		{
			//先拉低，给1us，等那边变化
			CHECK_ERROR(i2c_set_gpio_level_fun(i2c_handle->gpio_handle->gpio_scl, HIGH_LEVEL));
			CHECK_ERROR(i2c_delay_us_fun(1));
			temp = i2c_get_gpio_level_fun(i2c_handle->gpio_handle->gpio_sda);
			//I2C_LOGI("temp = %d\n", temp);
			byte |= temp << i;
			CHECK_ERROR(i2c_delay_us_fun(5));
			CHECK_ERROR(i2c_set_gpio_level_fun(i2c_handle->gpio_handle->gpio_scl, LOW_LEVEL));
			CHECK_ERROR(i2c_delay_us_fun(5));
			//CHECK_ERROR(i2c_delay_us_fun(5));
		}

		//i2c_ack_send(1);
		return byte;
	}
	return -1;
}

//先send地址，在发送是否写或者读标志位，在写数据
//addr要给出真实地址，不能靠左
void i2c_send_buf(uint8 addr, uint8 *buf, uint8 buf_len)
{
	uint8 t = 0;
	uint32 i = 0;
	t = addr & 0xFE;
	CHECK_ERROR(i2c_start());
	CHECK_ERROR(i2c_byte_send(t));
	CHECK_ERROR(i2c_delay_us_fun(10));
	for(i=0;i<buf_len;i++)
	{
		CHECK_ERROR(i2c_byte_send(buf[i]));
	}
	CHECK_ERROR(i2c_stop());
}

void i2c_send_reg_buf(uint8 addr, uint8 reg, uint8 *buf, uint8 buf_len)
{
	uint8 t = 0;
	uint32 i = 0;
	t = addr & 0xFE;
	CHECK_ERROR(i2c_start());
	CHECK_ERROR(i2c_byte_send(t));
	CHECK_ERROR(i2c_byte_send(reg));
	CHECK_ERROR(i2c_delay_us_fun(10));
	for(i=0;i<buf_len;i++)
	{
		CHECK_ERROR(i2c_byte_send(buf[i]));
	}
	CHECK_ERROR(i2c_stop());
}

//先send地址，在发送是否写或者读标志位，在读数据
//addr要给出真实地址，不能靠左
void i2c_read_buf(uint8 addr, uint8 *buf, uint8 buf_len)
{
	uint8 t = 0;
	uint32 i = 0;
	t = addr | 0x01;
	CHECK_ERROR(i2c_start());
	CHECK_ERROR(i2c_byte_send(t));
	CHECK_ERROR(i2c_delay_us_fun(10));
	for(i=0;i<buf_len;i++)
	{
		buf[i] = i2c_byte_read();
		I2C_LOGI("buf[%d] = 0x%02x\n", i, buf[i]);
		//发送数据前面的都发送OK，最后一个发送noack
		if(i <= buf_len-1)
			i2c_ack_send(1);
	}
	i2c_ack_send(0);
	CHECK_ERROR(i2c_stop());
}

void i2c_read_reg_buf(uint8 addr, uint8 reg, uint8 *buf, uint8 buf_len)
{
	uint8 t = 0;
	uint32 i = 0;
	t = addr & 0xFE;
	CHECK_ERROR(i2c_start());
	CHECK_ERROR(i2c_byte_send(t));
	CHECK_ERROR(i2c_byte_send(reg));
	CHECK_ERROR(i2c_delay_us_fun(10));
	t = addr | 0x01;
	CHECK_ERROR(i2c_start());
	CHECK_ERROR(i2c_byte_send(t));
	CHECK_ERROR(i2c_delay_us_fun(10));
	for(i=0;i<buf_len;i++)
	{
		buf[i] = i2c_byte_read();
		I2C_LOGI("buf[%d] = 0x%02x\n", i, buf[i]);
		//发送数据前面的都发送OK，最后一个发送noack
		if(i <= buf_len-1)
			i2c_ack_send(1);
	}
	i2c_ack_send(0);
	CHECK_ERROR(i2c_stop());
}




